<?php

declare(strict_types=1);

namespace App\Service\Client;


use App\Amqp\DelayProducer;
use App\Amqp\Producer\NoticeCertificationCompanyProducer;
use App\Constants\ErrorCode;
use App\Dao\AdminUserDao;
use App\Dao\CertificationCompanyApplyDao;
use App\Dao\CertificationIdcardDao;
use App\Dao\CertificationLogDao;
use App\Dao\NoticeAdminDao;
use App\Dao\UserEmployerDao;
use App\Exception\BusinessException;
use App\Model\CertificationCompanyApply;
use App\Model\CertificationIdcard;
use App\Model\CertificationLog;
use App\Model\UserEmployer;
use App\Utils\IDCard;
use App\Utils\Log;
use App\Utils\Notice\AdminCertificationCompanyAudit;
use App\Utils\Notice\Sender;
use Hyperf\Amqp\Result;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use App\Constants\Model\User as UserConstants;
use App\Constants\Model\UserEmployer as UserEmployerConstants;
use App\Constants\Model\CertificationLog as CertificationLogConstants;
use App\Constants\Model\CertificationCompanyApply as CertificationCompanyApplyConstants;
use App\Constants\Model\Notice as NoticeConstants;


class CertificationService extends BaseService
{
    /**
     * @Inject()
     * @var DelayProducer
     */
    protected $delayProducer;


    /**
     * @Inject()
     * @var UserEmployerDao
     */
    protected $userEmployer;

    /**
     * @Inject()
     * @var CertificationIdcardDao
     */
    protected $certificationIdcardDao;


    /**
     * @Inject()
     * @var AdminUserDao
     */
    protected $adminUserDao;

    /**
     * @Inject()
     * @var NoticeAdminDao
     */
    protected $noticeAdminDao;

    /**
     * @Inject()
     * @var CertificationLogDao
     */
    protected $certificationLogDao;

    /**
     * @Inject()
     * @var CertificationCompanyApplyDao
     */
    protected $certificationCompanyApplyDao;

    public function idcardInfo(): array
    {
        /** @var CertificationLog $certificationLog */
        $certificationLog = $this->certificationLogDao->first(
            ['user_id' => $this->userInfo()->id, 'status' => CertificationLogConstants::STATUS_SUCCESS]
        );

        $status = CertificationLogConstants::STATUS_NO;
        $idcard = '';
        $name = '';
        $created_at = '';
        if ($certificationLog) {
            $status = $certificationLog->status;
            $idcard = $certificationLog->idcard;
            $name = $certificationLog->name;
            $certificationLogArray = $certificationLog->toArray();
            $created_at = $certificationLogArray['created_at'];
        }

        return [
            'status' => $status,
            'idcard' => $idcard,
            'name' => $name,
            'created_at' => $created_at
        ];
    }


    /**
     * 实名认证-个人
     * @param array $data
     */
    public function idcard(array $data): void
    {
        if ($this->userinfo()->personal_certification == UserConstants::PERSONAL_CERTIFICATION_YES) {
            throw new BusinessException(ErrorCode::IDCARD_CERTIFICATION_PASS);
        }

        $certificationLogCount = CertificationLog::query()
            ->where('user_id', $this->userInfo()->id)
            ->where('created_at', '>=', date('Y-m-d') . ' 00:00:00')
            ->count();

        //每天只能提交3次
        if ($certificationLogCount >= CertificationLogConstants::DAY_MAX_SUBMIT_NUMBER) {
            throw new BusinessException(ErrorCode::IDCARD_CHECK_LIMIT);
        }

        /** @var CertificationIdcard $certificationIdcard */
        $certificationIdcard = $this->certificationIdcardDao->first(
            ['idcard' => $data['idcard'], 'name' => $data['name']]
        );

        $certificationLog = new CertificationLog();
        $certificationLog->user_id = $this->userInfo()->id;
        $certificationLog->idcard = $data['idcard'];
        $certificationLog->name = $data['name'];

        if ($certificationIdcard) {
            //身份库中已有
            $certificationLog->certification_idcard_id = $certificationIdcard->id;
            $certificationLog->status = CertificationLogConstants::STATUS_SUCCESS;
            $certificationLog->save();
        } else {
            //调用阿里接口校验
            $idcardResult = IDCard::check($data['idcard'], $data['name']);


            switch ((int)$idcardResult['code']) {
                case 0:
                    //1：一致； 2：不一致； 3：无法验证； -1：异常情况；
                    switch ((int)$idcardResult['data']['result']) {
                        case 1:
                            //验证成功
                            $certificationIdcard = new CertificationIdcard();
                            $certificationIdcard->idcard = $data['idcard'];
                            $certificationIdcard->name = $data['name'];
                            $certificationIdcard->save();

                            $certificationLog->certification_idcard_id = $certificationIdcard->id;
                            $certificationLog->status = CertificationLogConstants::STATUS_SUCCESS;
                            $certificationLog->save();
                            break;
                        case 2:
                            $certificationLog->status = CertificationLogConstants::STATUS_FAIL;
                            $certificationLog->save();
                            throw new BusinessException(ErrorCode::IDCARD_VERIFY_FAIL);
                            break;
                        case 3:
                            $certificationLog->status = CertificationLogConstants::STATUS_FAIL;
                            $certificationLog->save();
                            throw new BusinessException(ErrorCode::IDCARD_VERIFY_ERROR);
                            break;
                        case -1:
                            $certificationLog->status = CertificationLogConstants::STATUS_FAIL;
                            $certificationLog->save();
                            throw new BusinessException(ErrorCode::IDCARD_ERROR);
                            break;
                    }
                    break;
                case -1:
                    //服务或其他异常 - 未知异常
                    throw new BusinessException(ErrorCode::IDCARD_ERROR);
                    break;
                case 10016:
                    $certificationLog->status = CertificationLogConstants::STATUS_FAIL;
                    $certificationLog->save();
                    throw new BusinessException(ErrorCode::IDCARD_ERROR_NAME);
                    break;
                case 20010:
                    $certificationLog->status = CertificationLogConstants::STATUS_FAIL;
                    $certificationLog->save();
                    throw new BusinessException(ErrorCode::IDCARD_ERROR_ID);
                    break;
            }
        }


        Db::beginTransaction();
        try {
            $this->userInfo()->personal_certification = UserConstants::PERSONAL_CERTIFICATION_YES;
            $this->userInfo()->is_employer = UserConstants::IS_EMPLOYER_YES;
            $this->userInfo()->save();

            $userEmployer = $this->userEmployer->first(
                ['user_id' => $this->userInfo()->id]
            );
            if (!$userEmployer) {
                $userEmployer = new UserEmployer();
                $userEmployer->user_id = $this->userInfo()->id;
                $userEmployer->cooperative_id = $this->userInfo()->cooperative_id;
                $userEmployer->status = UserEmployerConstants::STATUS_UNBLOCK;
                $userEmployer->credit_point = UserEmployerConstants::DEFAULT_CREDIT_POINT;
                $userEmployer->shop_point = UserEmployerConstants::DEFAULT_SHOP_POINT;
                $userEmployer->balance = 0;
                $userEmployer->save();
            }
            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            Log::get()->error($e->getCode(), [$e->getMessage(), $data]);
            Log::get()->error($e->getTraceAsString());
            throw new BusinessException(ErrorCode::IDCARD_SUBMIT_ERROR);
        }
    }

    public function companyInfo()
    {
        /** @var CertificationCompanyApply $certificationCompanyApply */
        $certificationCompanyApply = $this->certificationCompanyApplyDao->first(
            [
                'user_id' => $this->userInfo()->id
            ]
        );

        $status = CertificationCompanyApplyConstants::STATUS_NO;
        $name = '';
        $credit_code = '';
        $license_img = '';
        $message = '';
        $created_at = '';

        if ($certificationCompanyApply) {
            $status = $certificationCompanyApply->status;
            $name = $certificationCompanyApply->name;
            $credit_code = $certificationCompanyApply->credit_code;
            $license_img = $certificationCompanyApply->license_img;
            $message = $certificationCompanyApply->message;
            $certificationCompanyApplyArray = $certificationCompanyApply->toArray();
            $created_at = $certificationCompanyApplyArray['created_at'];
        }


        return [
            'status' => $status,
            'name' => $name,
            'credit_code' => $credit_code,
            'license_img' => $license_img,
            'message' => $message,
            'created_at' => $created_at
        ];
    }

    /**
     * 实名认证-企业
     * @param array $data
     */
    public function company(array $data): void
    {
        /** @var CertificationCompanyApply $certificationCompanyApply */
        $certificationCompanyApply = $this->certificationCompanyApplyDao->first(
            ['user_id' => $this->userInfo()->id]
        );

        if ($certificationCompanyApply) {
            if (in_array(
                $certificationCompanyApply->status,
                [
                    CertificationCompanyApplyConstants::STATUS_ALLOW,
                    CertificationCompanyApplyConstants::STATUS_PENDING,
                ]
            )) {
                throw new BusinessException(ErrorCode::CERTIFICATION_COMPANY_HAS);
            }
        } else {
            $certificationCompanyApply = new CertificationCompanyApply();
        }

        Db::beginTransaction();
        try {
            $certificationCompanyApply->cooperative_id = $this->userInfo()->cooperative_id;
            $certificationCompanyApply->user_id = $this->userInfo()->id;
            $certificationCompanyApply->name = $data['name'];
            $certificationCompanyApply->credit_code = $data['credit_code'];
            $certificationCompanyApply->license_img = $data['license_img_id'];
            $certificationCompanyApply->status = CertificationCompanyApplyConstants::STATUS_PENDING;
            $certificationCompanyApply->save();

            //母公司通知-企业实名认证达5个
            $message = new NoticeCertificationCompanyProducer([]);
            $this->delayProducer->produce($message, 1);

            Db::commit();
        } catch (\Throwable $e) {
            Db::rollBack();
            Log::get()->error($e->getCode(), [$e->getMessage(), $data]);
            Log::get()->error($e->getTraceAsString());
//            var_dump($e->getMessage());
            throw new BusinessException(ErrorCode::CERTIFICATION_COMPANY_ERROR);
        }
    }


    /**
     * 母公司-企业审核通知（累计5条）
     * @return string
     */
    public function noticeCertificationCompany(): string
    {
        /**
         * 先查未审核数是否大于等于5
         * 获取所有用户
         * 判断两个小时之内是否有发过且未读
         * 无-发送，有忽略
         */
        $notAuditCount = CertificationCompanyApply::query()
            ->where('status', CertificationCompanyApplyConstants::STATUS_PENDING)
            ->count();

        if ($notAuditCount >= NoticeConstants::CERTIFICATION_COMPANY_NOT_AUDIT_MAX) {
            $adminIds = $this->adminUserDao->getIds();

            //判断两个小时内是否有发过且未读
            $beforeTime = time() - NoticeConstants::BEFORE_TIME_HAS_NOT_READ;
            $beforeDate = date('Y-m-d H:i:s', $beforeTime);

            $where = [
                'status' => NoticeConstants::STATUS_UNREAD,
                'created_at_gt' => $beforeDate,
                'admin_user_ids' => $adminIds
            ];
            $hasNotice = $this->noticeAdminDao->select($where);

            $hasNoticeIds = [];
            if ($hasNotice->count() > 0) {
                $hasNoticeArray = $hasNotice->toArray();
                $hasNoticeIds = array_column($hasNoticeArray, 'admin_user_id');
            }

            $needSendIds = array_diff($adminIds, $hasNoticeIds);

            if (count($needSendIds) > 0) {
                Sender::send(
                    $needSendIds,
                    new AdminCertificationCompanyAudit()
                );
            }
        }
        return Result::ACK;
    }

}